import json
from django import http
from decimal import Decimal

from django.core.paginator import Paginator
from django.shortcuts import render
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from areas.models import Address
from goods.models import SKU
from orders.models import OrderInfo, OrderGoods
from response_code import RET
from users.views import LoginRequired
from django.db import transaction #事务


class OrderSettlementView(LoginRequired):
    def get(self,request):
        user=request.user
        #获取地址
        addresses=user.addresses.filter(is_deleted=False)
        # <Address:1>:{"province":'','city':'', 'disc':'', 'receiver':''}
        #加总数据
        total_count=0
        total_amount=Decimal(0.0)
        freight=Decimal(10.0)
        payment_amount=0
        #获取商品数据
        redis_conn=get_redis_connection('carts')
        carts_dict=redis_conn.hgetall('carts_%s'%user.id)
        selected_list=redis_conn.smembers('selected_%s'%user.id)
        skus=[]
        for sku_id in selected_list:
            sku=SKU.objects.get(id=sku_id)
            sku_dict={
                'id':sku.id,
                'default_image_url':sku.default_image_url.url,
                'name':sku.name,
                'price':str(sku.price),
                'count':int(carts_dict[sku_id]),
                'amount':sku.price * int(carts_dict[sku_id]),
            }
            skus.append(sku_dict)
            total_count += sku_dict['count'] #数量
            total_amount = sku_dict['amount']#总价
        payment_amount = total_amount+freight #实际应付
        context={
            'addresses':addresses,
            'default_address_id':user.default_address_id,
            'skus':skus,
            'total_count':total_count,
            'total_amount':total_amount,
            'freight':freight,
            'payment_amount':payment_amount,
        }

        return render(request,'place_order.html',context=context)
class OrderCommitView(LoginRequired, View):
    def post(self,request):
        user=request.user
        data=json.loads(request.body.decode())
        address_id=data.get('address_id')
        pay_method=int(data.get('pay_method'))
        if not all([address_id, pay_method]):
            return http.HttpResponseForbidden("参数不全")
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '地址信息错误'})
        # if not pay_method in OrderInfo.PAY_METHODS_ENUM.values():
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '支付方式有误'})
        # 判断一下购物车的信息
        redis_conn = get_redis_connection('carts')
        carts_dict = redis_conn.hgetall('carts_%s' % user.id)
        selected_list = redis_conn.smembers('selected_%s' % user.id)
        if not selected_list:
            return http.JsonResponse({'code': RET.DATAERR, 'errmsg': '购物车信息有误'})
        #保存订单信息
        #构建订单编号(strftime是转换为特定格式输出，而strptime是将一个（时间）字符串解析为时间的一个类型对象)
        order_id=timezone.now().strftime('%Y%m%d%H%M%S')+"%06d"%user.id
        if pay_method==OrderInfo.PAY_METHODS_ENUM['CASH']:
            #货到付款>>待发货
            status=OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            # 支付宝付款>>待支付
            status = OrderInfo.ORDER_STATUS_ENUM["UNPAID"]
        #数据入库
        with transaction.atomic():
            save_id=transaction.savepoint()
            try:#若出现数据保存异常的情况
                order=OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal(0.0),
                    freight=Decimal(10.0),
                    pay_method=pay_method,
                    status=status,
                )
                #保存订单商品信息
                redis_conn=get_redis_connection('carts')
                cart_dict=redis_conn.hgetall('carts_%s'%user.id)
                cart_selected_list=redis_conn.smembers('selected_%s'%user.id)
                for sku_id in cart_selected_list:
                    while True:
                        sku = SKU.objects.get(id=sku_id)
                        count=int(cart_dict[sku_id])
                        if count>sku.stock:
                            #若判定一个订单中有部分商品库存不足，回滚
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RET.DATAERR, 'errmsg': '库存不足'})
                        #保存库存原始值：
                        old_sku_stock=sku.stock
                        old_sku_sales=sku.sales
                        import time
                        time.sleep(3)
                        # #库存充足的情况下，更新库存信息
                        # sku.stock-=count
                        # sku.sales+=count
                        # sku.save()
                        #到数据库二次校验库存无变动之后更改库存,内部会转成mysql语句执行
                        res=SKU.objects.filter(id=sku_id,stock=old_sku_stock,sales=old_sku_sales
                                           ).update(stock=old_sku_stock-count,sales=old_sku_sales+count)
                        if res==0:
                            # transaction.savepoint_rollback(save_id)
                            # return http.JsonResponse({'code':RET.DATAERR,'errmsg':'系统繁忙，请稍后再试'})
                            continue
                        # 修改SPU销量
                        sku.spu.sales += count
                        sku.spu.save()
                        break
                    # 创建订单商品信息对象
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=count,
                        price=sku.price,
                    )

                # 提交订单
                order.total_count += count
                order.total_amount += (count * sku.price)
                order.save()
            except Exception as e:
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code':RET.DBERR,'errmsg':'订单提交失败'})
            transaction.savepoint_commit(save_id)

        redis_conn.hdel('carts_%s'%user.id,*cart_selected_list)
        redis_conn.srem('selected_%s'%user.id,*cart_selected_list)
        res={
            'code': RET.OK,
            'errmsg': '提交成功',
            'order_id':order_id,
            'payment_amount':order.total_amount+order.freight,
            'pay_method':pay_method,}

        return http.JsonResponse(res)

class OrderSuccessView(LoginRequired):
    def get(self,request):
        #orders / success /?order_id = 20191013120204000008 & payment_amount = 7998 & pay_method = 2
        user=request.user
        order_id=request.GET.get('order_id')
        payment_amount=request.GET.get('payment_amount')
        pay_method=request.GET.get('pay_method')
        if not all([order_id, payment_amount, pay_method]):
            return http.HttpResponseForbidden('参数不全')
        try:
            OrderInfo.objects.get(order_id=order_id)
        except Exception as e:
            return http.HttpResponseForbidden('订单信息有误')
        context={
            'order_id':order_id,
            'payment_amount':payment_amount,
            'pay_method':pay_method,
        }
        return render(request,'order_success.html',context)
class UserOrderInfoView(LoginRequired):
    def get(self,request,page_num):
        user=request.user
        orders=user.orderinfo_set.all()
        #从model中取支付方式的名称
        '''    PAY_METHOD_CHOICES = (
            (1, "货到付款"),
            (2, "支付宝"),
        )'''
        # item>>(1, "货到付款");item[0]:item[1]>>{"1":"货到付款","2" :"支付宝"}
        pay_method_dict={item[0]: item[1] for item in OrderInfo.PAY_METHOD_CHOICES}
        status_name_dict={item[0]:item[1] for item in OrderInfo.ORDER_STATUS_CHOICES}
        order_list = []
        # 遍历所有订单
        for order in orders:
            order_data={
                'order_id': order.order_id,
                'create_time':order.create_time.strftime('%Y-%m-%d %H:%M:%S'),
                'total_amount':order.total_amount,
                'freight':order.freight,
                # 'pay_method_name':OrderInfo.PAY_METHOD_CHOICES[order.pay_method-1], #[(1, "货到付款"),(2, "支付宝")] [1]>>(2, "支付宝")[1]>>"支付宝",
                'pay_method_name':pay_method_dict.get(order.pay_method),
                'status':order.status,
                'status_name':status_name_dict.get(order.status), #根据key取到value{"1":"待支付"}
                'sku_list':[],
            }
            order_skus=order.skus.all().order_by("-create_time")
            for order_sku in order_skus:
                order_sku_data={
                    'default_image_url':order_sku.sku.default_image_url,
                    'name':order_sku.sku.name,
                    'price':order_sku.price,
                    'count':order_sku.count,
                    'amount':order_sku.price * order_sku.count,
                    'sku_id':order_sku.sku.id
                }
                order_data['sku_list'].append(order_sku_data)

            order_list.append(order_data)
        p=Paginator(order_list,per_page=2) #分页显示，包含了count对象总数、per_page每页对象个数、num_pages总页数
        current_page=p.page(int(page_num)) #当前页详情包含了：object_list对象列表、number页码、start_index()、end_index()
        # page_orders=current_page.object_list#当前页对象列表
        # total_page=p.num_pages #总页码
        context={
            'current_page':current_page.number,
            'total_page':p.num_pages,
            'page_orders':current_page.object_list
        }

        return render(request, "user_center_order.html", context=context)

class OrderCommentView(LoginRequired):
    def get(self,request):
        order_id=request.GET.get('order_id')
        try:
            OrderInfo.objects.get(order_id=order_id,user=request.user)
        except Exception as e:
            return http.HttpResponseNotFound('订单不存在')
        try:
            uncomment_goods=OrderGoods.objects.filter(order_id=order_id,is_commented=False)
        except Exception as e:
            return http.HttpResponseServerError('订单商品信息出错')
        uncomment_list=[]
        for goods in uncomment_goods:
            goods_data={
                'order_id':goods.order.order_id,
                'sku_id':goods.sku.id,
                'name':goods.sku.name,
                'price':str(goods.price),
                'default_image_url':goods.sku.default_image_url.url,
            }
            uncomment_list.append(goods_data)
        context = {
            'uncomment_goods_list': uncomment_list
        }
        return render(request,'goods_judge.html',context)

    def post(self, request):
        data=json.loads(request.body.decode())
        order_id=data.get('order_id')
        sku_id=data.get('sku_id')
        comment=data.get('comment')
        score=data.get('score')
        is_anonymous=data.get('is_anonymous') #是否匿名评价
        if not all([order_id, sku_id, score, comment]):
            return http.HttpResponseForbidden('缺少必传参数')
        try:
            OrderInfo.objects.filter(order_id=order_id,user=request.user,status=OrderInfo.ORDER_STATUS_ENUM['UNCOMMENT'])
        except Exception as e:
            return http.HttpResponseForbidden('参数order_id错误')
        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception as e:
            return http.HttpResponseForbidden('参数sku_id错误')
        if is_anonymous:
            if not isinstance(is_anonymous,bool):
                return http.HttpResponseForbidden('参数is_anonymous错误')
        # 保存订单商品评价数据
        OrderGoods.objects.filter(order_id=order_id,sku_id=sku_id,
        is_commented=False).update(
            comment=comment,
            score=score,
            is_anonymous=is_anonymous,
            is_commented=True
        )
        # 累计评论数据
        sku.comments += 1
        sku.save()
        sku.spu.comments += 1
        sku.spu.save()
        if OrderGoods.objects.filter(order_id=order_id,is_commented=False).count()==0:
            OrderInfo.objects.filter(order_id=order_id).update(status=OrderInfo.ORDER_STATUS_ENUM['FINISHED'])
        return http.JsonResponse({'code': RET.OK, 'errmsg': '评价成功'})

